package org.streets.workflow.engine.extension;

import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.streets.workflow.engine.ILoop;
import org.streets.workflow.engine.IProcessTrace;
import org.streets.workflow.engine.IToken;
import org.streets.workflow.engine.WorkflowContext;
import org.streets.workflow.engine.WorkflowException;
import org.streets.workflow.engine.condition.IConditionResolver;
import org.streets.workflow.engine.entities.ProcessTrace;
import org.streets.workflow.engine.entities.ProcessVariant;
import org.streets.workflow.engine.event.EdgeEvent;
import org.streets.workflow.engine.event.IEdgeEventListener;
import org.streets.workflow.engine.mem.Loop;
import org.streets.workflow.engine.plugin.INodeNetExtension;

/**
 * 
 */
public class LoopExtension implements INodeNetExtension, IEdgeEventListener {

	protected WorkflowContext rtCtx = null;

	public void setRuntimeContext(WorkflowContext ctx) {
		this.rtCtx = ctx;
	}

	public WorkflowContext getRuntimeContext() {
		return this.rtCtx;
	}

	public String getExtentionTargetName() {
		return Loop.Extension_Target_Name;
	}

	public String getExtentionPointName() {
		return Loop.Extension_Point_LoopInstanceEventListener;
	}

	/**
	 * @param vars
	 * @param condition
	 * @return
	 * @throws Exception
	 */
	private boolean determineTheAliveOfToken(String condition, List<ProcessVariant> vars) throws Exception {
		// 通过计算transition上的表达式来确定alive的值
		IConditionResolver elResolver = this.rtCtx.getConditionResolver();
		Map<String, Object> var_map = new HashMap<String, Object>();
		for (ProcessVariant var : vars) {
			var_map.put(var.getName(), var.getValue());
		}
		Boolean b = elResolver.resolveBooleanExpression(condition, var_map);

		return b;
	}

	/**
	 * @param token
	 * @param condition
	 * @throws WorkflowException
	 */
	public void calculateTheAliveValue(IToken token, String condition)throws WorkflowException {
		if (!token.isAlive()) {
			return;// 如果token是dead状态，表明synchronizer的joinpoint是dead状态，不需要重新计算。
		}

		// 1、如果没有循环条件，默认为false
		if (condition == null || condition.trim().equals("")) {
			token.setAlive(false);
			return;
		}
		// 3、计算EL表达式
		try {
			boolean alive = determineTheAliveOfToken(condition, token.getProcess().getVariables());
			token.setAlive(alive);
		} catch (Exception ex) {
			throw new WorkflowException(token.getProcess().getId(), token
					.getProcess().getModel(), token
					.getNodeId(), ex.getMessage());
		}
	}

	/* (non-Javadoc)
	 * @see org.fireflow.kernel.event.IEdgeInstanceEventListener#onEdgeInstanceEventFired(org.fireflow.kernel.event.EdgeInstanceEvent)
	 */
	public void onEdgeEventFired(EdgeEvent e)
			throws WorkflowException {

		if (e.getEventType() == EdgeEvent.ON_TAKING_THE_TOKEN) {
			IToken token = e.getToken();
			// 计算token的alive值
			ILoop transInst = (ILoop) e.getSource();
			String condition = transInst.getEdgeModel().getCondition();

			calculateTheAliveValue(token, condition);

			if (rtCtx.isEnableTrace() && token.isAlive()) {
				ProcessTrace trace = new ProcessTrace();
				trace.setProcessInstanceId(e.getToken().getProcess().getId());
				trace.setStepNum(e.getToken().getStepNumber() + 1);
				trace.setType(IProcessTrace.LOOP_TYPE);
				trace.setFromNodeId(transInst.getEdgeModel().getFromNode().getId());
				trace.setToNodeId(transInst.getEdgeModel().getToNode().getId());
				trace.setEdgeId(transInst.getEdgeId());
				//TODO wmj2003 一旦token从当前边上经过，那么就保存流程运行轨迹,这里应该是insert
				rtCtx.getPersistenceService().saveOrUpdateProcessTrace(
						trace);
			}
		}
	}
}
